package com.mezz.bones.framework.mybatis.dynamic.enhance;

import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.mezz.bones.framework.base.exception.BaseException;
import com.mezz.bones.framework.mybatis.dynamic.domain.dto.DynamicDataSourceInfo;
import com.mezz.bones.framework.mybatis.dynamic.provider.DataSourceInfoProvider;
import com.mezz.bones.framework.mybatis.dynamic.service.DataSourceCreatorService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.List;
import java.util.Map;

@Component
@Slf4j
public class EnhancedDynamicRoutingDataSource extends DynamicRoutingDataSource {

    @Resource
    private DataSourceInfoProvider dataSourceInfoProvider;

    @Resource
    private DataSourceCreatorService dataSourceCreatorService;

    @Resource
    private DynamicDataSourceProperties dataSourceProperties;

    // 严格匹配父类构造
    public EnhancedDynamicRoutingDataSource(List<DynamicDataSourceProvider> providers) {
        super(providers);
    }

    @PostConstruct
    public void init() {
        log.info("Dynamic datasource auto-init enabled");
    }

    /**
     * 路由数据源的入口
     * @return
     */
    @Override
    public DataSource determineDataSource() {

        //该key可由DynamicDataSourceHelper切换
        String dsKey = DynamicDataSourceContextHolder.peek();
        if (dsKey == null) {
            return getDefaultDataSource();
        }

        // 双重检查锁保证线程安全 保证只有一个线程会去执行初始连接操作
        if (!getDataSources().containsKey(dsKey)) {

            //项目可能是懒加载数据源 也可能是空闲状态该连接池被释放 可再次初始化
            synchronized (this) {
                if (!getDataSources().containsKey(dsKey)) {
                    initDataSource(dsKey);
                }
            }
        }
        return super.determineDataSource();
    }

    private DataSource getDefaultDataSource() {

        log.debug("dynamic-datasource switch to the primary datasource");
        DataSource dataSource = getDataSources().get(dataSourceProperties.getPrimary());
        if (dataSource == null) {
            throw new BaseException("The primary datasource is not configured");
        }

        return dataSource;
    }

    /**
     * 如果数据源不存在会去默认初始化该数据源
     * @param dsKey
     */
    private void initDataSource(String dsKey) {

        if (!StringUtils.hasText(dsKey)) {
            throw new IllegalArgumentException("initDataSource datasourceKey不能为空");
        }

        DynamicDataSourceInfo dataSourceInfo = dataSourceInfoProvider.loadDataSourceByKey(dsKey);

        if(dataSourceInfo == null) {
            throw new BaseException(StrUtil.format("loadDataSourceByKey not found datasourceKey[{}]", dsKey));
        }



        // 判断数据源是否已存在
        Map<String, DataSource> currentDataSources = super.getDataSources();
        if (currentDataSources.containsKey(dataSourceInfo.getDatasourceKey())) {
            //key不能重复定义
            throw new IllegalArgumentException(StrUtil.format("Datasource datasourceKey[{}]已存在，无法重复添加", dataSourceInfo.getDatasourceKey()));
        }

        super.addDataSource(dataSourceInfo.getDatasourceKey(), dataSourceCreatorService.createDatasource(dataSourceInfo));
    }
}